# _*_ coding:utf-8 _*_
import json
import os
import re
from typing import Any, Union, List

from jsonpath import jsonpath
from requests import Response

from Logs.log_handle import get_log
from tools.allure_step import allure_step
from tools.request_utils.pre_handle_utils import GLOBAL_VARS

log = get_log(os.path.split(__file__)[-1])


def after_extract(response: Response, exp) -> Union[List[str], None]:
    """
    提取响应中的参数，并将其存储到全局变量中，方便后续使用。

    :param response: requests 的响应对象
    :param exp: 需要提取的参数表达式，支持字典或 JSON 字符串，例如 '{"token": "$.data.token"}' 或 '{"k1": "data:(.*?)$"}'
    :return: None
    """
    if not exp:
        return

    # 如果 exp 为字符串，则尝试转换为字典
    if isinstance(exp, str):
        try:
            exp = json.loads(exp)
        except json.JSONDecodeError:
            log.error(f"无法解析提取表达式为 JSON: {exp}")
            return

    # 判断响应内容的类型（JSON 或字符串），选择合适的提取器
    if response_type(response) == "json":
        res_content = response.json()
        extractor = json_extractor
    else:
        res_content = response.text
        extractor = re_extract

    # 遍历提取表达式，提取并存储参数到全局变量 GLOBAL_VARS 中
    extracted_list = []
    for index, (k, v) in enumerate(exp.items(), start=1):
        GLOBAL_VARS[k] = extractor(res_content, v)
        # kv = f"第{index}个 => {k}: {v} -> {GLOBAL_VARS[k]}"
        kv = f" {k}: {v} -> {GLOBAL_VARS[k]}"
        extracted_list.append(kv)

    allure_step("提取后的参数数据", extracted_list)
    return extracted_list


def response_type(response: Response) -> str:
    """
    判断响应数据的类型，返回 "json" 或 "str"。

    :param response: requests 返回对象
    :return: 响应数据类型字符串 "json" 或 "str"
    """
    try:
        response.json()
        return "json"
    except ValueError:
        return "str"


def json_extractor(obj: Any, expr: Union[str, dict] = "$") -> Union[Any, None]:
    """
    从 JSON 对象中提取数据。

    :param obj: JSON/字典类型数据
    :param expr: 提取表达式，例如 $.code 提取一级字典的 code 字段；也支持传入一个字典，针对多个字段进行提取
    :return: 提取的结果，未提取到返回 None
    """
    try:
        # 如果 obj 是字典，将其转换为 JSON 字符串，以便统一后续处理
        if isinstance(obj, dict):
            obj = json.dumps(obj)

        # 如果 expr 为字典，则对每个 key 执行提取操作
        if isinstance(expr, dict):
            result = {key: jsonpath(json.loads(obj), path) for key, path in expr.items()}
        else:
            result = jsonpath(json.loads(obj), expr)
            result = result[0] if result else None

        log.info(f"提取响应内容成功，表达式：{expr}，提取值：{result}")
    except Exception as e:
        log.exception(f"提取失败，表达式：{expr}，错误信息：{str(e)}")
        result = None

    return result


def re_extract(obj: str, expr: str = ".") -> Union[Any, None]:
    """
    从字符串中提取匹配内容。

    :param obj: 字符串数据
    :param expr: 正则表达式
    :return: 提取的结果，未提取到返回 None
    """
    try:
        result = re.findall(expr, obj)
        result = result[0] if result else None
        log.info(f"提取内容成功，表达式：{expr}，提取值：{result}")
    except Exception as e:
        log.exception(f"正则提取失败，表达式：{expr}，错误信息：{str(e)}")
        result = None

    return result
